package com.kb.medical.controller;

import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.kb.medical.entity.User;
import com.kb.medical.service.IUserService;
import com.kb.medical.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;


//@Controller
@RestController//@Controller+@ResponseBody
@RequestMapping("users")
public class UserController extends BaseController {
    //    设置上传文件的最大值
    public static final int AVATAR_MAX_SIZE = 10 * 1024 * 1024;
    //  限制上传的类型
    public static final List<String> AVATAR_TYPE = new ArrayList<String>();

    static {
        AVATAR_TYPE.add("image/jpeg");
        AVATAR_TYPE.add("image/png");
        AVATAR_TYPE.add("image/bmp");
        AVATAR_TYPE.add("image/gif");
    }

    @Autowired
    private IUserService userService;

    /**
     * 约定大于配置:开发思想来完成，省略带大量的配置甚至注解的编写
     * 1、接收数据方式:请求处理方法的参数列表设置为pojo类型来接收前端的数据,
     * SpringBoot会将前端的url地址中参数名和pojo类的属性名进行比较，如果
     * 这两个名称项目，则将值注入到pojo类中对应的属性上
     */
    @RequestMapping("reg")
    @ResponseBody//表示此方法的响应结果以json格式进行数福的响应给到前端
    public JsonResult<Void> reg(User user) {
        //创建响应结果对象
        userService.reg(user);
        JsonResult result = new JsonResult<>(OK);
        result.setState(200);
        result.setMessage("注册成功！");
        return result;
    }

    /**
     * 2、接收数据方式:请求处理方法的参数列表设置为非pojo类型
     * SpringBoot会直接将请求的参数名和方法的参数名直接进行比较，如果
     * 这两个名称项目相同则将值的依赖注入
     */
    @RequestMapping("login")
    @ResponseBody//表示此方法的响应结果以json格式进行数福的响应给到前端
//    public JsonResult<User> login(String username,String password){
//        User data = userService.login(username, password);
//        return new JsonResult<User>(OK,data);
//    }

    public JsonResult Login(String username,
                            String password) {
        User data = userService.login(username, password);
        int id = data.getUserid();
        // 第二步：根据账号id，进行登录
        // 		此处填入的参数应该保持用户表唯一，比如用户id，不可以直接填入整个 User 对象
        StpUtil.login(id);
        // SaResult 是 Sa-Token 中对返回结果的简单封装，下面的示例将不再赘述
        JsonResult result = new JsonResult<>(OK);
        result.setState(200);
        result.setMessage("登陆成功");
        // 第2步，获取 Token  相关参数
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        result.setData(tokenInfo);
        // 第3步，返回给前端
        return result;
    }

    @RequestMapping("change_password")
    @ResponseBody//表示此方法的响应结果以json格式进行数福的响应给到前端
    public JsonResult<Void> changePassword(String oldPassword,
                                           String newPassword) {
// 校验当前客户端是否已经登录，如果未登录则抛出 `NotLoginException` 异常
        try {
            StpUtil.getTokenInfo().getIsLogin();//检测是否登录
        } catch (SaTokenException e) {
            throw new SaTokenException(401);
        }

        User data = userService.getByUserid(StpUtil.getLoginIdAsInt()); //查询当前的用户id
        int userid = StpUtil.getLoginIdAsInt(); //查询当前的用户id
        String username = data.getUsername();
        userService.changePassword(userid, username, oldPassword, newPassword);
        JsonResult result = new JsonResult<>(OK);
        result.setState(200);
        result.setMessage("修改成功");
        return result;
    }

    @RequestMapping("get_by_userid")
    @ResponseBody//表示此方法的响应结果以json格式进行数福的响应给到前端
    public JsonResult<User> getByUserId() {
        // 校验当前客户端是否已经登录，如果未登录则抛出 `NotLoginException` 异常
        try {
            StpUtil.getTokenInfo().getIsLogin();//检测是否登录
        } catch (SaTokenException e) {
            throw new SaTokenException("用户没有登陆").setCode(401);
        }
        // 需要注意的是，StpUtil.getLoginId() 自带登录校验效果
        // 也就是说如果在未登录的情况下调用这句代码，框架就会抛出 `NotLoginException` 异常，效果和 StpUtil.checkLogin() 是一样的
        System.out.println(StpUtil.getLoginId());
        User data = userService.getByUserid(StpUtil.getLoginIdAsInt()); //查询当前的用户id
//        User data = userService.getByUserid(userid); //查询当前的用户id
        return new JsonResult<User>(OK, data);
    }

    @RequestMapping("change_info")
    @ResponseBody//表示此方法的响应结果以json格式进行数福的响应给到前端
    public JsonResult<Void> changeInfo(User user) {
        // 校验当前客户端是否已经登录，如果未登录则抛出 `NotLoginException` 异常

        //user对象有四部分的数据：username、phone、email、gender
        //userid数据需要再次封装到user对象中
        try {
            StpUtil.getTokenInfo().getIsLogin();//检测是否登录
        } catch (Exception e) {
            throw new SaTokenException("用户没有登陆").setCode(401);
        }
        User data = userService.getByUserid(StpUtil.getLoginIdAsInt()); //查询当前的用户id
        userService.changeInfo(data.getUserid(), data.getUsername(), user);
        JsonResult result = new JsonResult<>(OK);
        result.setState(200);
        result.setMessage("修改成功！");
        return result;
    }

    /**
     * MultipartFile接口是SpringMVC提供一个接口，这个接口为我们包装了
     * 获取文件类型的数据（任何类型的file都可以接受），SpringBoot它有整合了
     * SpringMVC，只需要在处理请求的方法参数列表上声明一个参数类型为MultipartFile
     * 的参数，然后SpringBoot自动将传递给服务的文件数据赋值给这个参数
     *
     * @param
     * @return
     * @RequestParam 表示请求中的参数，请求中的参数注入请求处理放方法的某个
     * 参数上，如果名称不一致则可以使用@RequestParam注解进行标记和映射
     */
//    @GetMapping("change_avatar")
//    public JsonResult<String> changeAvatar(MultipartFile file) {
//        // 校验当前客户端是否已经登录，如果未登录则抛出 `NotLoginException` 异常
//        try {
//            StpUtil.getTokenInfo().getIsLogin();//检测是否登录
//        }catch (Exception e) {
//            throw new SaTokenException("用户没有登陆").setCode(401);
//        }
//        User data = userService.getByUserid(StpUtil.getLoginIdAsInt()); //查询当前的用户id
//        //判断文件是否为null
//        if (file.isEmpty()) {
//            throw new FileEmptyException("文件为空");
//        }
//        //判断文件的类型是否是我们规定的和后缀类型
//        String contentType = file.getContentType();
//        //如果集合包含某个元素则返回true
//        if (!AVATAR_TYPE.contains(contentType)) {
//            throw new FileTypeNotMatchException("文件类型不支持");
//        }
//
//        if (file.getSize() > AVATAR_MAX_SIZE) {
//            throw new FileSizeException("文件过大，上传失败");
//        }
//
//        //获取到这个文件名称，UUID工具来将生成一个新的字符串作为文件名
//        //例如：avatar01.png
//        String originalFilename = file.getOriginalFilename();
//
//        System.out.println("originalFilename=" + originalFilename);
//
//        //获取文件的后缀名
//        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
//
//        //使用时间戳为文件定义新的名字
//        String uuidName = UUID.randomUUID().toString();
//
//        //定义文件最终的名字
//        String fileName = uuidName + suffix;
//
//        //获取项目在服务器上的真实位置并拼凑文件最终的保存位置
//        //本地的写法
//        String realPath = System.getProperty("user.dir") + "src/main/resources/img" + fileName;
//
//        //线上服务器的写法
////        String realPath = filePath + fileName;
//        /**
//         * 这里其实有两个选择：①直接将文件写入硬盘 这里选择这种
//         * ②先获取存储文件的文件夹的路径，判断存储文件的文件夹是否存在，不存在则创建
//         * 最后再将文件名和文件夹路径进行拼凑出最终文件的保存路径
//         **/
//        //虚拟创建目标文件
//        File destFile = new File(realPath);
//
//        //获取目标文件的上级目录
//        File parentFile = destFile.getParentFile();
//
//        if (!parentFile.exists()) {
//            //代表文件的上级目录不存在，进行创建
//            parentFile.mkdirs();
//        }
//
//        //选择第一种方法，直接写入目标位置
//        try {
//            file.transferTo(destFile);
//        } catch (FileStatusException e) {
//            throw new FileStatusException("文件状态异常，写入失败");
//        } catch (IOException e) {
//            throw new FileUploadIOException("服务器或数据库写入文件失败");
//        }
//
//        //获取userid值
//
//        int userid = StpUtil.getLoginIdAsInt(); //查询当前的用户id
//
//        String username = data.getUsername();
//        //返回头像的路径/upload/test.png
//        String avatar = "/upload" + fileName;
//        userService.changeAvatar(userid, avatar, username);
//        //返回用户头像的路径给前端，将来用于头像展示使用
//        return new JsonResult<>(OK, avatar);
//    }


//    //    头像上传
//    @PostMapping("/uploadAvatar")
//    public SaResult uploadAvatar(MultipartFile file) {
//        SaResult result = new SaResult();
//        if (file.isEmpty()) {
//            result.setCode(402);
//            result.setMsg("上传图片为空");
//            return result;
//        }
//
//    }
    @RequestMapping("suggest")
    @ResponseBody//表示此方法的响应结果以json格式进行数福的响应给到前端
    public JsonResult suggest(String suggest) {
        try {
            StpUtil.getTokenInfo().getIsLogin();//检测是否登录
        } catch (Exception e) {
            throw new SaTokenException("用户没有登陆").setCode(401);
        }
        User data = userService.getByUserid(StpUtil.getLoginIdAsInt()); //查询当前的用户id
        userService.insertSuggest(data.getUserid(), suggest);
        JsonResult result = new JsonResult<>(OK);
        result.setState(200);
        result.setMessage("发送成功！");
        return result;
    }


    //处理用户退出登录的请求
    @RequestMapping("logout")
    public SaResult logout() {
        // 退出登录会清除三个地方的数据：
        // 		1、Redis中保存的 Token 信息
        // 		2、当前请求上下文中保存的 Token 信息
        // 		3、Cookie 中保存的 Token 信息（如果未使用Cookie模式则不会清除）
        StpUtil.logout();
        StpUtil.logoutByTokenValue(StpUtil.getTokenValue());

        // StpUtil.logout() 在未登录时也是可以调用成功的，
        // 也就是说，无论客户端有没有登录，执行完 StpUtil.logout() 后，都会处于未登录状态
        System.out.println("当前是否处于登录状态：" + StpUtil.isLogin());

        // 返回给前端
        return SaResult.ok("退出登录成功");
    }

//    @RequestMapping("chat")
//    public SaResult chatgpt() {
//        String token = "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";//System.getenv("OPENAI_TOKEN");
//        OpenAiService service = new OpenAiService(token);
//        CompletionRequest completionRequest = CompletionRequest.builder()
//                .model("text-davinci-003")
//                .prompt("今天天气怎么样？")
//                .temperature(0.5)
//                .maxTokens(2048)
//                .topP(1D)
//                .frequencyPenalty(0D)
//                .presencePenalty(0D)
//                .build();
//        service.createCompletion(completionRequest).getChoices().forEach(System.out::println);
//        SaResult.data(service);
//        return SaResult.ok("ok");
//    }
}


